package com.quectel.core.module;

import com.quectel.constant.core.ResourceGroupCodeConstants;
import com.quectel.constant.global.SystemConstants;
import com.quectel.constant.sys.SysConstants;
import com.quectel.core.module.device.dto.DeviceCategoryDto;
import com.quectel.core.module.device.dto.DeviceTypeDto;
import com.quectel.core.module.group.dto.SysGroupBuildingDto;
import com.quectel.core.module.group.dto.SysGroupVillageDto;
import com.quectel.core.module.group.service.*;
import com.quectel.core.module.resource.dto.ResourceGroupDto;
import com.quectel.core.module.resource.service.ResourceGroupService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * mongodb统一封装权限 仿照BaseAuth.xml
 * <p>
 * 这个类使用起来请注意 mongodb不允许在一个and下出现两个相同的字段所以尽量按照下列方法
 * <p>
 * <p>
 * Criteria authByAllQuery = mongoAuthComponent.buildAuthByAllQuery(params, "deviceDto.tenantId",
 * "deviceDto.deviceCategoryId", "deviceDto.deviceTypeId",
 * "deviceDto._id", "deviceDto.VillageId");
 * <p>
 * Criteria otherFieldQuery = new Criteria();
 * if (startTime != null && endTime != null) {
 * otherFieldQuery.and("sendTime").gte(startTime).lte(endTime);
 * }
 * if (deviceId != null) {
 * otherFieldQuery.and("deviceDto._id").is(deviceId);
 * }
 * <p>
 * new Query(new Criteria().andOperator(authByAllQuery, otherFieldQuery)
 *
 * @author: CL
 * @email: louis.cao@quectel.com
 * @date: 2022-03-16 10:43:00
 */
@Component
public class MongoAuthComponent {
    private static final String SESSION_NAME = "_loginUserSession";
    private static final String SYS_GROUP_NAME = "_sysGroup";
    private static final String RESOURCE_GROUP_CODE = ResourceGroupCodeConstants.AUTH_RESOURCE_GROUP_CODE_FLAG;

    private static final String TENANT_ID = "tenantId";
    private static final String GROUP_CODE = "code";
    private static final String AUTH_TYPE = "authorityType";
    @Autowired
    private SysGroupDeviceService sysGroupDeviceService;
    @Autowired
    private SysGroupDeviceCategoryService sysGroupDeviceCategoryService;
    @Autowired
    private SysGroupDeviceTypeService sysGroupDeviceTypeService;
    @Autowired
    private SysGroupVillageService sysGroupVillageService;
    @Autowired
    private SysGroupRegionService sysGroupRegionService;
    @Autowired
    private SysRegionVillageRefService sysRegionVillageRefService;
    @Autowired
    private SysGroupBuildingService sysGroupBuildingService;

    @Autowired
    private ResourceGroupService resourceGroupService;

    /**
     * 是否包含权限信息
     *
     * @param authParams
     * @return
     */
    private boolean hasAuthInfo(Map<String, Object> authParams) {
        return authParams.get(SESSION_NAME) != null && authParams.get(SYS_GROUP_NAME) != null;
    }

    /**
     * 构建租户过滤查询依赖
     *
     * @param authParams
     * @param tenantFieldName deviceDto.tenantId
     * @return
     */
    public Criteria buildTenantConstraintsQuery(Map<String, Object> authParams, String tenantFieldName) {
        Criteria criteria = new Criteria();
        if (!hasAuthInfo(authParams)) {
            return criteria;
        }
        Map<String, Object> loginUserSession = (Map<String, Object>) authParams.get(SESSION_NAME);
        if (loginUserSession != null) {
            criteria.andOperator(Criteria.where(tenantFieldName).is(loginUserSession.get(TENANT_ID)));
        }
        return criteria;
    }

    /**
     * 构建设备种类和设备类型过滤查询依赖
     *
     * @param authParams
     * @param tenantFieldName           deviceDto.tenantId
     * @param deviceCategoryIdFieldName deviceDto.deviceCategoryId
     * @param deviceTypeIdFieldName     deviceDto.deviceTypeId
     * @return
     */
    public Criteria buildAuthByDeviceCategoryAndTypeQuery(Map<String, Object> authParams, String tenantFieldName,
                                                          String deviceCategoryIdFieldName, String deviceTypeIdFieldName
    ) {
        Criteria criteria = new Criteria();

        if (!hasAuthInfo(authParams)) {
            return criteria;
        }

        Map<String, Object> sysGroup = (Map<String, Object>) authParams.get(SYS_GROUP_NAME);

        Byte authType = sysGroup.get(AUTH_TYPE) == null ? SystemConstants.ABNORMAL : Byte.valueOf(sysGroup.get(AUTH_TYPE) + "");

        if (!SysConstants.SYS_TOP_GROUP_CODE.equals(sysGroup.get(GROUP_CODE) + "")) {
            if (SysConstants.GroupAuthEnum.BY_TYPE.getType().equals(authType)) {
                //种类或者类型
                List<DeviceCategoryDto> categories = sysGroupDeviceCategoryService.selectByGroupId(Long.valueOf(sysGroup.get(SystemConstants.ENTITY_ID_FLAG) + ""));
                List<DeviceTypeDto> types = sysGroupDeviceTypeService.selectByGroupId(Long.valueOf(sysGroup.get(SystemConstants.ENTITY_ID_FLAG) + ""));
                Criteria orCondition = new Criteria().
                        orOperator(Criteria.where(deviceCategoryIdFieldName).in(categories.stream().map(DeviceCategoryDto::getId).collect(Collectors.toList())),
                                Criteria.where(deviceTypeIdFieldName).in(types.stream().map(DeviceTypeDto::getId).collect(Collectors.toList())));

                criteria.andOperator(orCondition);
            }
        }

        return new Criteria().andOperator(buildTenantConstraintsQuery(authParams, tenantFieldName), criteria);
    }

    /**
     * 构建社区过滤查询依赖
     *
     * @param authParams
     * @param tenantFieldName    deviceDto.tenantId
     * @param VillageIdFieldName deviceDto.VillageId
     * @return
     */
    public Criteria buildAuthByRegionOrVillageQuery(Map<String, Object> authParams, String tenantFieldName,
                                                    String VillageIdFieldName
    ) {
        Criteria criteria = new Criteria();

        if (!hasAuthInfo(authParams)) {
            return criteria;
        }

        Map<String, Object> sysGroup = (Map<String, Object>) authParams.get(SYS_GROUP_NAME);

        Byte authType = sysGroup.get(AUTH_TYPE) == null ? SystemConstants.ABNORMAL : Byte.valueOf(sysGroup.get(AUTH_TYPE) + "");

        if (sysGroup != null && !SysConstants.SYS_TOP_GROUP_CODE.equals(sysGroup.get(GROUP_CODE) + "")) {
            if (SysConstants.GroupAuthEnum.BY_VILLAGE.getType().equals(authType)) {
                //社区或者区域
                List<SysGroupVillageDto> Villages = sysGroupVillageService.queryListByGroupId(Long.valueOf(sysGroup.get(SystemConstants.ENTITY_ID_FLAG) + ""));
                criteria.andOperator(Criteria.where(VillageIdFieldName).in(Villages.stream().map(SysGroupVillageDto::getVillageId).collect(Collectors.toList())));
            } else if (SysConstants.GroupAuthEnum.BY_REGION.getType().equals(authType)) {
                //社区或者区域
                //翻译成社区
                sysRegionVillageRefService.executeRef((Long.valueOf(sysGroup.get(SystemConstants.ENTITY_ID_FLAG) + "")));
                List<SysGroupVillageDto> Villages = sysGroupVillageService.queryListByGroupId(Long.valueOf(sysGroup.get(SystemConstants.ENTITY_ID_FLAG) + ""));
                criteria.andOperator(Criteria.where(VillageIdFieldName).in(Villages.stream().map(SysGroupVillageDto::getVillageId).collect(Collectors.toList())));
            } else {
                //查询越界 强制查询结果集为空
                criteria.andOperator(Criteria.where(SystemConstants.MONGO_ENTITY_ID_FLAG).is(SystemConstants.NONEXISTENT_ID));
            }
        }

        return new Criteria().andOperator(buildTenantConstraintsQuery(authParams, tenantFieldName), criteria);
    }

    /**
     * 构建社区楼栋过滤查询依赖
     *
     * @param authParams
     * @param tenantFieldName     deviceDto.tenantId
     * @param VillageIdFieldName  deviceDto.VillageId
     * @param buildingIdFieldName deviceDto.buildingId
     * @return
     */
    public Criteria buildAuthByRegionOrVillageOrBuildingQuery(Map<String, Object> authParams, String tenantFieldName,
                                                              String VillageIdFieldName, String buildingIdFieldName
    ) {
        Criteria criteria = new Criteria();


        if (!hasAuthInfo(authParams)) {
            return criteria;
        }

        Map<String, Object> sysGroup = (Map<String, Object>) authParams.get(SYS_GROUP_NAME);

        Byte authType = sysGroup.get(AUTH_TYPE) == null ? SystemConstants.ABNORMAL : Byte.valueOf(sysGroup.get(AUTH_TYPE) + "");

        if (sysGroup != null && !SysConstants.SYS_TOP_GROUP_CODE.equals(sysGroup.get(GROUP_CODE) + "")) {
            if (SysConstants.GroupAuthEnum.BY_VILLAGE.getType().equals(authType)) {
                //社区或者区域
                List<SysGroupVillageDto> Villages = sysGroupVillageService.queryListByGroupId(Long.valueOf(sysGroup.get(SystemConstants.ENTITY_ID_FLAG) + ""));
                criteria.andOperator(Criteria.where(VillageIdFieldName).in(Villages.stream().map(SysGroupVillageDto::getVillageId).collect(Collectors.toList())));
            } else if (SysConstants.GroupAuthEnum.BY_REGION.getType().equals(authType)) {
                //社区或者区域
                //翻译成社区
                sysRegionVillageRefService.executeRef((Long.valueOf(sysGroup.get(SystemConstants.ENTITY_ID_FLAG) + "")));
                List<SysGroupVillageDto> Villages = sysGroupVillageService.queryListByGroupId(Long.valueOf(sysGroup.get(SystemConstants.ENTITY_ID_FLAG) + ""));
                criteria.andOperator(Criteria.where(VillageIdFieldName).in(Villages.stream().map(SysGroupVillageDto::getVillageId).collect(Collectors.toList())));
            } else if (SysConstants.GroupAuthEnum.BY_BUILDING.getType().equals(authType)) {
                //楼栋
                List<SysGroupBuildingDto> Villages = sysGroupBuildingService.queryListByGroupId(Long.valueOf(sysGroup.get(SystemConstants.ENTITY_ID_FLAG) + ""));
                criteria.andOperator(Criteria.where(VillageIdFieldName).in(Villages.stream().map(SysGroupBuildingDto::getBuildingId).collect(Collectors.toList())));
            } else {
                //查询越界 强制查询结果集为空
                criteria.andOperator(Criteria.where(SystemConstants.MONGO_ENTITY_ID_FLAG).is(SystemConstants.NONEXISTENT_ID));
            }
        }

        return new Criteria().andOperator(buildTenantConstraintsQuery(authParams, tenantFieldName), criteria);
    }

    /**
     * 构建全部过滤查询依赖
     *
     * @param authParams
     * @param tenantFieldName           deviceDto.tenantId
     * @param deviceCategoryIdFieldName deviceDto.deviceCategoryId
     * @param deviceTypeIdFieldName     deviceDto.deviceTypeId
     * @param deviceIdFiledName         deviceDto._id
     * @param VillageIdFieldName        deviceDto.VillageId
     * @param buildingIdFieldName       deviceDto.buildingId
     * @return
     */
    public Criteria buildAuthByAllQuery(Map<String, Object> authParams, String tenantFieldName,
                                        String deviceCategoryIdFieldName, String deviceTypeIdFieldName,
                                        String deviceIdFiledName, String VillageIdFieldName, String buildingIdFieldName
    ) {

        Criteria deviceCriteria = new Criteria();

        if (!hasAuthInfo(authParams)) {
            return deviceCriteria;
        }

        Map<String, Object> sysGroup = (Map<String, Object>) authParams.get(SYS_GROUP_NAME);

        Byte authType = sysGroup.get(AUTH_TYPE) == null ? SystemConstants.ABNORMAL : Byte.valueOf(sysGroup.get(AUTH_TYPE) + "");

        if (sysGroup != null && !SysConstants.SYS_TOP_GROUP_CODE.equals(sysGroup.get(GROUP_CODE) + "")) {
            if (SysConstants.GroupAuthEnum.BY_DEVICE.getType().equals(authType)) {
                List<Long> deviceIds = sysGroupDeviceService.selectByGroupId(Long.valueOf(sysGroup.get(SystemConstants.ENTITY_ID_FLAG) + ""));
                //设备
                deviceCriteria.andOperator(Criteria.where(deviceIdFiledName).in(deviceIds));
            }
        }
        return new Criteria().andOperator(
                buildTenantConstraintsQuery(authParams, tenantFieldName),
                buildAuthByDeviceCategoryAndTypeQuery(authParams, tenantFieldName, deviceCategoryIdFieldName, deviceTypeIdFieldName),
                buildAuthByRegionOrVillageOrBuildingQuery(authParams, tenantFieldName, VillageIdFieldName, buildingIdFieldName),
                deviceCriteria
        );
    }

    /**
     * 构建资源code过滤查询依赖
     *
     * @param authParams
     * @param deviceCategoryIdFieldName deviceDto.deviceCategoryId
     * @param deviceTypeIdFieldName     deviceDto.deviceTypeId
     * @return
     */
    public Criteria buildFilterByResourceGroupQuery(Map<String, Object> authParams,
                                                    String deviceCategoryIdFieldName, String deviceTypeIdFieldName
    ) {
        Criteria criteria = new Criteria();

        String resourceCode = (String) authParams.get(RESOURCE_GROUP_CODE);
        if (StringUtils.isNotBlank(resourceCode)) {
            ResourceGroupDto resourceGroupDto = resourceGroupService.selectByCacheCode(resourceCode);
            Criteria orCondition = new Criteria().
                    orOperator(Criteria.where(deviceCategoryIdFieldName).in(resourceGroupDto.getDeviceCategorys().stream().map(DeviceCategoryDto::getId).collect(Collectors.toList())),
                            Criteria.where(deviceTypeIdFieldName).in(resourceGroupDto.getDeviceTypes().stream().map(DeviceTypeDto::getId).collect(Collectors.toList())));

            criteria.andOperator(orCondition);
        }

        return criteria;
    }
}
